package com.spider;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;

//自定义窗口类，创建对象，展示主窗口
public class MainFrame extends JFrame {
    //设置照片位置
    private String imagePath = "stone-maze/src/image/";
    //准备一个数组，用户存放数字色块的行列位置。
    private int[][] imageData = {
            {1,2,3,4},
            {5,6,7,8},
            {9,10,11,12},
            {13,14,15,0}
    };
    private int[][] winData = {
            {1,2,3,4},
            {5,6,7,8},
            {9,10,11,12},
            {13,14,15,0}
    };
    //定义两个整数，记录空块的行列位置
    private int row;// 行
    private int col;// 列
    private int count = 0;// 记录步数
    private JLabel stepLabel; // 步数标签
    private int minCount;
    private JLabel minCountLabel;   // 历史最小步数标签
    public MainFrame() {
        //1.调用一个初始化方法，初始化窗口大小
        initFrame();
        //4.打乱数组
        shuffleSolvable();
        minCount =  readMinCount();//文件中的最小步数。
        //2.初始化界面，展示数字色块。
        initImage();
        //3.初始化系统菜单，点击弹出菜单信息是系统退出，重启游戏
        initMenu();
        //5.给当前窗口绑定上下左右按键事件。
        initKeyPressEvent();
        //设置窗口可见
        this.setVisible(true);


    }
    private void shuffleSolvable() {
        java.util.List<Integer> nums = new java.util.ArrayList<>();
        for (int i = 0; i < 16; i++) nums.add(i);

        // 随机洗牌直到可解
        do {
            java.util.Collections.shuffle(nums);
        } while (!isSolvable(nums));

        // 放回 imageData
        int index = 0;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                imageData[i][j] = nums.get(index++);
                if (imageData[i][j] == 0) {
                    row = i; col = j;
                }
            }
        }
    }

    private boolean isSolvable(java.util.List<Integer> nums) {
        int inversions = 0;
        for (int i = 0; i < 16; i++) {
            for (int j = i + 1; j < 16; j++) {
                if (nums.get(i) != 0 && nums.get(j) != 0 && nums.get(i) > nums.get(j)) {
                    inversions++;
                }
            }
        }

        int blankRowFromBottom = 3 - (nums.indexOf(0) / 4);

        return (inversions + blankRowFromBottom) % 2 == 0;
    }

    //读取文件中的最少步数
private int readMinCount() {
    int readminCount = Integer.MAX_VALUE;
    try(FileReader fr = new FileReader("D:\\CODE\\study_-java\\ai-java-project\\stone-maze\\src\\Count.txt");
        BufferedReader br = new BufferedReader(fr);
    ){

        String line = br.readLine();
        if (line != null) {
            readminCount = Integer.parseInt(line.trim());
        }

    }catch (Exception e){
        System.out.println("读取失败，路径：" + new File("src/Count.txt").getAbsolutePath());
        e.printStackTrace();

    }
    return readminCount;
}
    // ★★★ 写入新的最小步数
    private void writeMinCount(int newMin) {
        try(FileWriter fw = new FileWriter("D:\\CODE\\study_-java\\ai-java-project\\stone-maze\\src\\Count.txt")){
            fw.write(String.valueOf(newMin));
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    private void initKeyPressEvent() {
        //给当前窗口绑定上下左右按键事件。
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //获取按键的键值
                int keyCode = e.getKeyCode();
                //判断按键的键值
                switch (keyCode){
                    case KeyEvent.VK_UP:
                        //按下了上键
                        switchAndMove(Direction.UP);
                        break;
                    case KeyEvent.VK_DOWN:
                        //按下了下键
                        switchAndMove( Direction.DOWN);
                        break;
                    case KeyEvent.VK_LEFT:
                        //按下了左键
                        switchAndMove( Direction.LEFT);
                        break;
                    case KeyEvent.VK_RIGHT:
                        //按下了右键
                        switchAndMove( Direction.RIGHT);
                        break;
                }
                if(isWin()){
                    onWin();
                }
            }
        });
    }
    // ★★★ 胜利后的处理逻辑
    private void onWin() {
        // 当前步数比历史记录小 → 更新文件
        if (count < minCount) {
            minCount = count;
            writeMinCount(minCount);

            // 更新界面显示
            if (minCountLabel != null) {
                minCountLabel.setText("历史胜利最少步数：" + minCount + "步");
            }

            JOptionPane.showMessageDialog(this,
                    "恭喜！你创下新纪录：" + minCount + "步！",
                    "新纪录",
                    JOptionPane.INFORMATION_MESSAGE);
        } else {
            JOptionPane.showMessageDialog(this,
                    "恭喜通关！总步数：" + count + "步\n当前最小记录：" + minCount + "步",
                    "胜利",
                    JOptionPane.INFORMATION_MESSAGE);
        }

        initImage();
    }
    private void switchAndMove(Direction direction) {
        //控制图片移动
        switch (direction){
            case UP:
                //上交换的条件是行必须小于3
                if (row <3){
                   int temp = imageData[row][col];
                   imageData[row][col] = imageData[row+1][col];
                   imageData[row+1][col] = temp;
                   row++;
                   count++;
                }
                break;
            case DOWN:
                //下交换的条件是行必须大于0
                if (row > 0){
                    int temp = imageData[row][col];
                    imageData[row][col] = imageData[row-1][col];
                    imageData[row-1][col] = temp;
                    row--;
                    count++;
                }
                break;
            case LEFT:
                //左交换的条件是列必须大于0
                if (col < 3){
                    int temp = imageData[row][col];
                    imageData[row][col] = imageData[row][col+1];
                    imageData[row][col+1] = temp;
                    col++;
                    count++;
                }
                break;
            case RIGHT:
                //右交换的条件是列必须小于3
                if (col > 0){
                    int temp = imageData[row][col];
                    imageData[row][col] = imageData[row][col-1];
                    imageData[row][col-1] = temp;
                    col--;
                    count++;
                }
                break;
        }
        updateStepLabel();
        initImage();
    }

    private void updateStepLabel() {
            if (stepLabel != null) {
                stepLabel.setText("步数：" + count);
            }
    }

    private void initRandomArray() {
        for (int i = 0; i < imageData.length; i++) {
            for (int j = 0; j < imageData[i].length; j++) {
              //随机两个行列位置，让这两个位置交换
                int x = (int)(Math.random()*imageData.length);
                int y = (int)(Math.random()*imageData.length);
                int temp = imageData[i][j];
                imageData[i][j] = imageData[x][y];
                imageData[x][y] = temp;
            }
        }
        //定位空白色块的位置
        //去二维数组中遍历每个数据，只要发现这个数据等于0，则记录这个位置的行和列
        OUT:
        for (int i = 0; i < imageData.length; i++) {
            for (int j = 0; j < imageData[i].length; j++) {
                if (imageData[i][j] == 0){
                    row = i;
                    col = j;
                    break  OUT;//跳出循环
                }
            }
        }

}




    private void initMenu() {
        JMenuBar menuBar = new JMenuBar();//创建菜单栏
        JMenu menu = new JMenu("系统");//创建菜单
        JMenuItem exitJi = new JMenuItem("退出");//创建菜单项
        menu.add(exitJi);//添加菜单项
        exitJi.addActionListener(e -> {
            dispose();
        });
        JMenuItem restartJi = new JMenuItem("重启");
        menu.add(restartJi);
        restartJi.addActionListener(e -> {
            //重新启动游戏
            initRandomArray();
            count = 0;
            updateStepLabel();
            initImage();
        });
        menuBar.add(menu);//添加菜单

        // ------- 历史胜利最少步数显示 -------
        minCountLabel= new JLabel("历史胜利最少步数："+ minCount+"步");
        minCountLabel.setFont(new Font("微软雅黑", Font.BOLD, 15));
        minCountLabel.setForeground(new Color(50, 50, 50));
        minCountLabel.setBorder(BorderFactory.createEmptyBorder(0, 30, 0, 0));
        menuBar.add(minCountLabel);

        // ------- 步数显示 -------
        stepLabel = new JLabel("步数：0");
        stepLabel.setFont(new Font("微软雅黑", Font.BOLD, 15));
        stepLabel.setForeground(new Color(50, 50, 50));
        stepLabel.setBorder(BorderFactory.createEmptyBorder(0, 30, 0, 0)); // 左边距
        menuBar.add(Box.createHorizontalGlue()); // 把步数推到右侧
        menuBar.add(stepLabel);

        this.setJMenuBar(menuBar);// 添加菜单栏
    }

    private void initImage() {

        //先清空窗口上的全部图层
        this.getContentPane().removeAll();


        //判断是否赢了,重新设计一个方法判断
        if (isWin()){
            JLabel winLabel = new JLabel(new ImageIcon(imagePath+"win.png"));
            winLabel.setBounds(124,0,230,88);
            this.add(winLabel);
        }
        //1.展示一个行列矩阵的数字色块依次铺满窗口（4*4）
        for (int i = 0; i < imageData.length; i++) {
            for (int j = 0; j < imageData[i].length; j++) {
                //拿到图片的名称
                String imageName = imageData[i][j] + ".png";
                //创建一个JLabel对象，设置图片给他展示
                JLabel label = new JLabel();
                //设置图片
                label.setIcon(new ImageIcon( imagePath+imageName));
                //设置图片的位置
                label.setBounds(20+j*100,60+i*100,100,100);
                //把图片展示到窗口上
                this.add(label);
            }
        }
        //设置窗口的背景图片
        JLabel background = new JLabel(new ImageIcon(imagePath+"background.png"));
        background.setBounds(0,0,450,484);
        this.add(background);

        //再刷新图层
        this.repaint();
    }

    private boolean isWin() {
        for (int i = 0; i < imageData.length; i++) {
            for (int j = 0; j < imageData[i].length; j++) {
                if (imageData[i][j] != winData[i][j]){
                    return false;
                }
            }
        }
        return true;
    }


    private void initFrame() {
        this.setTitle("石头迷阵");
        this.setSize(465, 575);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
        this.setLayout( null);
    }
}
